package com.itheima.a11;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
* jdk静态代理是jdk自带的代理技术，并且需要目标对象实现某个接口
* 那jdk的动态代理跟目标是什么关系，其实是兄弟关系，因为jdk的动态代理和目标类都实现了同样的接口
* 是平级别的兄弟关系，那么他们可以使用强制类型转换吗，不能实现强制类型转换，他们都能转换成他们的接口类型
* 但是不能相互转换。
* 并且需要注意的是使用jdk的代理技术，需要扩展的目标类也可以为final类型的，因为它们是兄弟关系，不存在继承
* */
public class JdkProxyDemo {

    interface Foo {
        void foo();
    }

    static final class Target implements Foo {
        public void foo() {
            System.out.println("target foo");
        }
    }

    // jdk 只能针对接口代理
    // cglib
    public static void main(String[] param) throws IOException {
        // 目标对象
        Target target = new Target();

        ClassLoader loader = JdkProxyDemo.class.getClassLoader(); // 用来加载在运行期间动态生成的字节码
        /*创建一个新的代理实例对象*/
        /*需要三个参数，
        第一个参数是类加载器，用于加载代理类内部生成的字节码；
        第二个参数是你将来要生成的这个代理，实现时，要实现什么样的接口；
        第三个参数是InvocationHandler这么一个接口，可以使用lambda表达式来实现；
        第三个参数用于代理类创建出来了，也实现这个接口了，需要实现接口中的抽象方法，你必须规定方法中的行为，
        InvocationHandler就是用于把行为进行封装，
        */
        Foo proxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object p, Method method, Object[] args) throws Throwable {
                /*前置增强*/
                System.out.println("before...");
                // 目标.方法(参数)
                // 方法.invoke(目标, 参数);
                /*反射调用，让代理也返回目标方法执行的结果*/
                Object result = method.invoke(target, args);
                /*后置增强*/
                System.out.println("after....");
                return result; // 让代理也返回目标方法执行的结果
            }
        });

        System.out.println(proxy.getClass());

        /*下面的调用就会执行到invoke里面的代码了*/
        proxy.foo();

        System.in.read();
    }
}